package br.ufrgs.meetapp.models;

import java.util.ArrayList;

import android.content.Context;
import br.ufrgs.meetapp.enums.SettingsComponent;
import br.ufrgs.meetapp.utils.UserPreferencesPersistence;


/***
 * Class for modeling the SettingsActivity interaction with the shared preferences
 * @author Benites
 *
 */
public class MFTSettings {
	
	private ArrayList<SettingsEntry> settingsEntryList;
	private Context context;
	
	// General defaults
	/**
	 * Specify the default time interval to acquire a new position.
	 */
	public static final int DEFAULT_TIME_INTERVAL_MILLIS = 1800000; //30 minutes
	
	/**
	 * Specify the default time interval to send positions.
	 */
	public static final int DEFAULT_SEND_INTERVAL_MILLIS = 10000; // 10 seconds
	
	/**
	 * Specify the default acquiring timeout (time trying to acquire a position from GPS)
	 */
	public static final int DEFAULT_ACQUIREMENT_TIMEOUT_MILLIS = 120000; // 2 minutes
	
	/**
	 * Specify if the tracker is on by default or don't
	 */
	public static final boolean DEFAULT_IS_TRACKER_OFF = false;
	
	/**
	 * Specify if the feature to track other devices is on or off by default
	 */
	public static final boolean DEFAULT_IS_TRACKER_OTHERS_ON = true;
	
	
	// Threshold related defaults
	/***
	 * Default distance interval to send a new position message. Each time the user reaches that number of meters(default) a new position message must be queued to be sent by sender server.
	 */
	public static final int DEFAULT_DISTANCE_INTERVAL_METERS = 1000; // 1km
	
	/***
	 * Default speed in kilometers per hour that the user is considered moving. Each time the user reached this speed (default) it is considered moving and the position service must be started 
	 */
	public static final int DEFAULT_MOTION_SPEED_THRESHOLD_KM_H = 15;// 15km/h
	
	/***
	 * Default time in milliseconds that the user needs to be considered stopped to stop position service (e.g under the speed considered moving). If the user is considered stopped this number of milliseconds (default) the position service must be stopped. 
	 */
	public static final int DEFAULT_MOTION_STOP_THRESHOLD_MILLIS = 300000; // 5 minutes
	
	/***
	 * Default angle change in degrees send a new position message. Each time the user changes it's direction that number of degrees (default) a new position message must be queued to be sent by sender server.
	 */
	public static final int DEFAULT_COURSE_RANGE_DEGREES = 40; //40 degrees
	
	
	private final int POWER_SAFE_BY_MOVEMENT_DETECTION_PRESET = 0;
	private final int POWER_SAFE_PRESET = 1;
	private final int ALWAYS_ON_PRESET = 2;
	
	public MFTSettings(Context _context) {
		context = _context;
		settingsEntryList = new ArrayList<SettingsEntry>();
		settingsEntryList.add(new SettingsEntry(SettingsComponent.TRACKER_OFF, UserPreferencesPersistence.getIsTrackerOff(context))); 
		settingsEntryList.add(new SettingsEntry(SettingsComponent.TRACKER_OTHERS_ON, UserPreferencesPersistence.getIsTrackOthersOn(context))); 
		settingsEntryList.add(new SettingsEntry(SettingsComponent.TIME_INTERVAL, UserPreferencesPersistence.getTimeInterval(context))); 
		settingsEntryList.add(new SettingsEntry(SettingsComponent.SENDING_INTERVAL, UserPreferencesPersistence.getSendingInterval(context))); 
		settingsEntryList.add(new SettingsEntry(SettingsComponent.DISTANCE_INTERVAL, UserPreferencesPersistence.getDistanceInterval(context)));
		settingsEntryList.add(new SettingsEntry(SettingsComponent.MOTION_SPEED_THRESHOLD  , UserPreferencesPersistence.getMotionSpeedThreshold(context)));  
		settingsEntryList.add(new SettingsEntry(SettingsComponent.MOTION_STOP_THRESHOLD, UserPreferencesPersistence.getMotionStopThreshold(context))); 
		settingsEntryList.add(new SettingsEntry(SettingsComponent.COURSE_RANGE, UserPreferencesPersistence.getCourseRange(context))); 
		settingsEntryList.add(new SettingsEntry(SettingsComponent.ACQUIRE_TIMEOUT, UserPreferencesPersistence.getAcquireTimeout(context)));
	}
	
	/***
	 * Get the latest values for the settings form the shared preferences
	 */
	public void refresh() {
		setValue(SettingsComponent.TRACKER_OFF, UserPreferencesPersistence.getIsTrackerOff(context));
		setValue(SettingsComponent.TRACKER_OTHERS_ON, UserPreferencesPersistence.getIsTrackOthersOn(context));
		setValue(SettingsComponent.TIME_INTERVAL, UserPreferencesPersistence.getTimeInterval(context));
		setValue(SettingsComponent.SENDING_INTERVAL, UserPreferencesPersistence.getSendingInterval(context));
		setValue(SettingsComponent.DISTANCE_INTERVAL, UserPreferencesPersistence.getDistanceInterval(context));
		setValue(SettingsComponent.MOTION_SPEED_THRESHOLD, UserPreferencesPersistence.getMotionSpeedThreshold(context));
		setValue(SettingsComponent.MOTION_STOP_THRESHOLD, UserPreferencesPersistence.getMotionStopThreshold(context));
		setValue(SettingsComponent.COURSE_RANGE, UserPreferencesPersistence.getCourseRange(context));
		setValue(SettingsComponent.ACQUIRE_TIMEOUT, UserPreferencesPersistence.getAcquireTimeout(context));
	}
	
	/***
	 * Get the corresponding settings component value (Note that the values comes from this settings object, not from shared preferences)
	 * @param settingsComponent
	 * @return - correspondent value
	 */
	public Object getValue(SettingsComponent settingsComponent) {
		Object value = "";
		for (SettingsEntry settingsEntry : settingsEntryList) {
			
			if (settingsEntry.getKey().equals(settingsComponent)){
				value = settingsEntry.getValue();
			}
		}
		return value;
	}
	
	
	/***
	 * Set the specified settings component with the specified value
	 * @param settingsComponent
	 * @param value
	 */
	public void setValue(SettingsComponent settingsComponent, Object value) {
		SettingsEntry settingsEntry = getSettingsEntry(settingsComponent);
		settingsEntry.setValue(value);
	}
	
	/***
	 * Get the key/value entry object corresponding settings component key
	 * @param settingsComponent
	 * @return
	 */
	private SettingsEntry getSettingsEntry(SettingsComponent settingsComponent) {
		
		SettingsEntry settingsEntryResult = null; 
		
		for (SettingsEntry settingsEntry : settingsEntryList) {
			
			if (settingsEntry.getKey().equals(settingsComponent)){
				settingsEntryResult = settingsEntry;
			}
		}
		
		return settingsEntryResult;
	}
	
	/***
	 * Return the settings object settings entry (key/value) list
	 * @return
	 */
	public ArrayList<SettingsEntry> getSettingsEntryList() {
		return settingsEntryList;
	}
	
	/***
	 * Set the specified code preset of values
	 * @param presetCode
	 */
	public void setPreset(int presetCode) {
		
		switch (presetCode) {
		case ALWAYS_ON_PRESET:
			setAlwaysOnPreset();
			break;
		case POWER_SAFE_PRESET:
			setPowerSafePreset();
			break;
		case POWER_SAFE_BY_MOVEMENT_DETECTION_PRESET:
			setPowerSafeMovementDetectionPreset();
			break;
		default:
			break;
		}
		
	}
	
	/***
	 * Set always on preset values
	 */
	private void setAlwaysOnPreset() {
		setValue(SettingsComponent.TIME_INTERVAL, 60000);
		setValue(SettingsComponent.MOTION_SPEED_THRESHOLD, 15);
		setValue(SettingsComponent.MOTION_STOP_THRESHOLD, 300000);
		setValue(SettingsComponent.DISTANCE_INTERVAL, 500);
		setValue(SettingsComponent.COURSE_RANGE, 40);
		setValue(SettingsComponent.SENDING_INTERVAL, 10000);
		setValue(SettingsComponent.ACQUIRE_TIMEOUT, 120000);
	}
	
	/***
	 * Set power safe preset values
	 */
	private void setPowerSafePreset() {
		setValue(SettingsComponent.TIME_INTERVAL, 1800000);
		setValue(SettingsComponent.MOTION_SPEED_THRESHOLD, 0);
		setValue(SettingsComponent.MOTION_STOP_THRESHOLD, 0);
		setValue(SettingsComponent.DISTANCE_INTERVAL, 1000);
		setValue(SettingsComponent.COURSE_RANGE, 40);
		setValue(SettingsComponent.SENDING_INTERVAL, 600000);
		setValue(SettingsComponent.ACQUIRE_TIMEOUT, 120000);
	}
	
	/***
	 * Set power safe by movement detection preset values
	 */
	private void setPowerSafeMovementDetectionPreset() {
		setValue(SettingsComponent.TIME_INTERVAL, 1800000);
		setValue(SettingsComponent.MOTION_SPEED_THRESHOLD, 15);
		setValue(SettingsComponent.MOTION_STOP_THRESHOLD, 300000);
		setValue(SettingsComponent.DISTANCE_INTERVAL, 1000);
		setValue(SettingsComponent.COURSE_RANGE, 40);
		setValue(SettingsComponent.SENDING_INTERVAL, 10000);
		setValue(SettingsComponent.ACQUIRE_TIMEOUT, 120000);
	}
	
	/***
	 * Persist this settings object values in the shared preferences
	 * @return true with successfully persisted, false otherwise 
	 */
	public boolean save(){
		return UserPreferencesPersistence.updateSettings(context, this);
	}
	
	/**
	 * Verify if the settings have changed
	 * @return true if has changed, false otherwise
	 */
	public boolean hasChanged(){
		
		boolean changed = false;
		if (((Boolean)getValue(SettingsComponent.TRACKER_OFF)) != UserPreferencesPersistence.getIsTrackerOff(context)){
			changed = true;
		} else if ((((Boolean)getValue(SettingsComponent.TRACKER_OTHERS_ON)) != UserPreferencesPersistence.getIsTrackOthersOn(context))){
			changed = true;
		} else if ((((Integer)getValue(SettingsComponent.TIME_INTERVAL)) != UserPreferencesPersistence.getTimeInterval(context))){
			changed = true;
		} else if ((((Integer)getValue(SettingsComponent.SENDING_INTERVAL)) != UserPreferencesPersistence.getSendingInterval(context))){
			changed = true;
		} else if ((((Integer)getValue(SettingsComponent.DISTANCE_INTERVAL)) != UserPreferencesPersistence.getDistanceInterval(context))){
			changed = true;
		} else if ((((Integer)getValue(SettingsComponent.MOTION_SPEED_THRESHOLD)) != UserPreferencesPersistence.getMotionSpeedThreshold(context))){
			changed = true;
		} else if ((((Integer)getValue(SettingsComponent.MOTION_STOP_THRESHOLD)) != UserPreferencesPersistence.getMotionStopThreshold(context))){
			changed = true;
		} else if ((((Integer)getValue(SettingsComponent.COURSE_RANGE)) != UserPreferencesPersistence.getCourseRange(context))){
			changed = true;
		} else if ((((Integer)getValue(SettingsComponent.ACQUIRE_TIMEOUT)) != UserPreferencesPersistence.getAcquireTimeout(context))){
			changed = true;
		}
	
		return changed;
	}
	
	public void setServerUpdates(byte[] settings){
		UserPreferencesPersistence.setPresetSelected(context, 3);
		String settingsAsString = new String(settings);
		settingsAsString = settingsAsString.replaceAll("\r\n", ";");
		String[] settingsList = settingsAsString.split(";");
		for(String setting : settingsList){
			String[] settingKeyValue = setting.split(":");
			String settingKey = settingKeyValue[0];
			String settingValue = settingKeyValue[1];
			if(!settingValue.equals("0")){
				try{
					SettingsComponent settingEnum = SettingsComponent.fromServerLabelString(settingKey);
					if(settingEnum != null){
						setValue(settingEnum, Integer.parseInt(settingValue));
					}
				} catch (Exception e) {
					System.out.println("Key not found");
				}
			}
		}
		save();
		refresh();
	}
	
}


